package com.gl.doc.operation.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.ZipUtil;
import com.gl.doc.builder.WordDocument;
import com.gl.doc.model.Paragraph;
import com.gl.doc.model.Word;
import com.gl.doc.model.WordComment;
import com.gl.doc.model.container.WordXmlContainer;
import com.gl.doc.operation.WordOperation;
import com.gl.doc.operation.comment.BindComment;
import com.gl.doc.operation.comment.DoBindComment;
import com.gl.doc.operation.comment.bindcomment.CaseOneBindComment;
import com.gl.doc.operation.comment.bindcomment.CaseSecondBindComment;
import com.gl.doc.operation.comment.entity.WordCommentRelation;
import com.gl.doc.operation.comment.impl.DefaultBindComment;
import com.gl.doc.path.TempPath;
import com.gl.doc.support.ParagraphLookupSupport;
import com.gl.doc.support.XmlSupport;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * word文档操作默认实现
 */
@Slf4j
public class DefaultWordOperation implements WordOperation {
    /**
     * 绑定批注接口
     */
    private final BindComment bindComment = new DefaultBindComment();

    {
        //初始化批注绑定条件判断情况
        DefaultBindComment defaultBindComment = (DefaultBindComment) bindComment;
        List<DoBindComment> doBindComments = new ArrayList<>();
        defaultBindComment.setDoBindComments(doBindComments);
        //第一种段落里面只有一个子段落
        doBindComments.add(new CaseOneBindComment());
        //第二种段落里面有两个以上子段落
        doBindComments.add(new CaseSecondBindComment());
    }

    @Override
    public void addWordComment(WordComment wordComment, WordDocument wordDocument) {
        Word word = wordDocument.getWord();
        File commentFile = new File(word.getCommentsPath());
        if (!commentFile.exists()) {
            this.addWordCommentRelation(wordDocument, commentFile);
        }
        this.addParagraphComment(wordComment, wordDocument);
    }

    @Override
    public Word parseWord(File file) {
        String tempPath = TempPath.getTempPath();
        String fileName = file.getName();
        fileName = fileName.replace(".docx", ".zip");
        File docFile = new File(tempPath + "/" + fileName);
        try (
                BufferedInputStream is = FileUtil.getInputStream(file);
                BufferedOutputStream os = FileUtil.getOutputStream(docFile);
        ) {
            IoUtil.copy(is, os);
        } catch (Exception e) {
            log.error("解析失败!", e);
        }
        return this.getWord(tempPath, docFile);
    }

    @Override
    public Word parseWord(InputStream inputStream) {
        String tempPath = TempPath.getTempPath();
        File docFile = new File(tempPath + "/" + "xxx.zip");
        try (
                BufferedInputStream is = new BufferedInputStream(inputStream);
                BufferedOutputStream os = FileUtil.getOutputStream(docFile);
        ) {
            IoUtil.copy(is, os);
        } catch (Exception e) {
            log.error("解析失败!", e);
        }
        return this.getWord(tempPath, docFile);
    }

    /**
     * 添加word文档批注文件引用的关系
     *
     * @param wordDocument word文档对象
     * @param commentFile  批注xml文件
     */
    private void addWordCommentRelation(WordDocument wordDocument, File commentFile) {
        try (
                InputStream is = this.getClass().getClassLoader().getResourceAsStream("comments.xml");
                BufferedOutputStream os = FileUtil.getOutputStream(commentFile);
        ) {
            IoUtil.copy(is, os);
            Word word = wordDocument.getWord();
            WordXmlContainer wordXmlContainer = wordDocument.getWordXmlContainer();
            //批注引用添加到[Content_Types].xml
            String contentTypesCommentsXml = wordXmlContainer.getWordXmlString("[Content_Types].xml-comments");
            String contentTypesCommentsExtendedXml = wordXmlContainer.getWordXmlString("[Content_Types].xml-commentsExtended");
            File contentTypesFile = new File(word.getContentTypesPath());
            XmlSupport.addElement(contentTypesFile, contentTypesCommentsXml);
            XmlSupport.addElement(contentTypesFile, contentTypesCommentsExtendedXml);
            //批注引用添加到document.xml.rels
            File documentRelationFile = new File(word.getDocumentRelationPath());
            String docRelsPeopleXml = wordXmlContainer.getWordXmlString("document.xml-people");
            String docRelsCommentsXml = wordXmlContainer.getWordXmlString("document.xml-comments");
            String docRelsCommentsExtendedXml = wordXmlContainer.getWordXmlString("document.xml-commentsExtended");
            this.addDocRelation(documentRelationFile, docRelsPeopleXml);
            this.addDocRelation(documentRelationFile, docRelsCommentsXml);
            this.addDocRelation(documentRelationFile, docRelsCommentsExtendedXml);
        } catch (Exception e) {
            log.error("word添加批注关系失败!", e);
        }
    }

    /**
     * 添加一段关系
     *
     * @param documentRelationFile 文档关系xml文件
     * @param xml                  xml字符串
     */
    private void addDocRelation(File documentRelationFile, String xml) {
        FileReader fileReader = new FileReader(documentRelationFile);
        String docRelationships = fileReader.readString();
        docRelationships = docRelationships.replace("</Relationships>", "<" + xml + "/>");
        docRelationships += "</Relationships>";
        FileWriter fileWriter = new FileWriter(documentRelationFile);
        fileWriter.write(docRelationships);
    }

    /**
     * 添加段落批注
     *
     * @param wordComment  批注对象
     * @param wordDocument word文档对象
     */
    private void addParagraphComment(WordComment wordComment, WordDocument wordDocument) {
        try {
            Word word = wordDocument.getWord();
            Document document = ParagraphLookupSupport.paragraphLookup(wordDocument, newTargetParagraph -> {
                Paragraph targetParagraph = wordComment.getTargetParagraph();
                String targetIdPath = targetParagraph.getIdPath();
                if (targetIdPath.equals(newTargetParagraph.getIdPath())) {
                    wordComment.setTargetParagraph(newTargetParagraph);
                    bindComment.addParagraphComment(new WordCommentRelation(wordComment, wordDocument));
                }
            });
            File documentFile = new File(word.getDocumentPath());
            XmlSupport.writer(document, documentFile);
        } catch (Exception e) {
            log.error("word绑定批注失败!", e);
        }
    }

    /**
     * 获取word文档
     *
     * @param tempPath 临时路径
     * @param docFile  docx文件
     * @return Word结构
     */
    private Word getWord(String tempPath, File docFile) {
        File zipFile = ZipUtil.unzip(docFile);
        Word word = new Word();
        word.setTempPath(tempPath);
        word.setFile(zipFile);
        word.setContextPath(zipFile.getAbsolutePath());
        word.setContentTypesPath(zipFile.getAbsolutePath() + "/[Content_Types].xml");
        word.setCommentsPath(zipFile.getAbsolutePath() + "/word/comments.xml");
        word.setDocumentPath(zipFile.getAbsolutePath() + "/word/document.xml");
        word.setDocumentRelationPath(zipFile.getAbsolutePath() + "/word/_rels/document.xml.rels");
        return word;
    }
}
